/**
 * jQuery Yii ListView plugin file.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @link http://www.yiiframework.com/
 * @copyright 2008-2010 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

;(function ($) {
  var yiiXHR = {};
  /**
   * yiiListView set function.
   * @param options map settings for the list view. Availablel options are as follows:
   * - ajaxUpdate: array, IDs of the containers whose content may be updated by ajax response
   * - ajaxVar: string, the name of the request variable indicating the ID of the element triggering the AJAX request
   * - ajaxType: string, the type (GET or POST) of the AJAX request
   * - pagerClass: string, the CSS class for the pager container
   * - sorterClass: string, the CSS class for the sorter container
   * - updateSelector: string, the selector for choosing which elements can trigger ajax requests
   * - beforeAjaxUpdate: function, the function to be called before ajax request is sent
   * - afterAjaxUpdate: function, the function to be called after ajax response is received
   */
  $.fn.yiiListView = function (options) {
    return this.each(function () {
      var settings = $.extend({}, $.fn.yiiListView.defaults, options || {}),
        $this = $(this),
        id = $this.attr('id');

      if (settings.updateSelector == undefined) {
        settings.updateSelector = '#' + id + ' .' + settings.pagerClass.replace(/\s+/g, '.') + ' a, #' + id + ' .' + settings.sorterClass.replace(/\s+/g, '.') + ' a';
      }
      $.fn.yiiListView.settings[id] = settings;

      if (settings.ajaxUpdate.length > 0) {
        $(document).on('click.yiiListView', settings.updateSelector, function () {
          if (settings.enableHistory && window.History.enabled) {
            var url = $(this).attr('href').split('?'),
              params = $.deparam.querystring('?' + (url[1] || ''));

            delete params[settings.ajaxVar];
            window.History.pushState(null, document.title, decodeURIComponent($.param.querystring(url[0], params)));
          } else {
            $.fn.yiiListView.update(id, {url: $(this).attr('href')});
          }
          return false;
        });

        if (settings.enableHistory && window.History.enabled) {
          $(window).bind('statechange', function () { // Note: We are using statechange instead of popstate
            var State = window.History.getState(); // Note: We are using History.getState() instead of event.state
            $.fn.yiiListView.update(id, {url: State.url});
          });
        }
      }
    });
  };

  $.fn.yiiListView.defaults = {
    ajaxUpdate: [],
    ajaxVar: 'ajax',
    ajaxType: 'GET',
    pagerClass: 'pager',
    loadingClass: 'loading',
    sorterClass: 'sorter'
    // updateSelector: '#id .pager a, '#id .sort a',
    // beforeAjaxUpdate: function(id) {},
    // afterAjaxUpdate: function(id, data) {},
    // url: 'ajax request URL'
  };

  $.fn.yiiListView.settings = {};

  /**
   * Returns the key value for the specified row
   * @param id string the ID of the list view container
   * @param index integer the zero-based index of the data item
   * @return string the key value
   */
  $.fn.yiiListView.getKey = function (id, index) {
    return $('#' + id + ' > div.keys > span:eq(' + index + ')').text();
  };

  /**
   * Returns the URL that generates the list view content.
   * @param id string the ID of the list view container
   * @return string the URL that generates the list view content.
   */
  $.fn.yiiListView.getUrl = function (id) {
    var settings = $.fn.yiiListView.settings[id];
    return settings.url || $('#' + id + ' > div.keys').attr('title');
  };

  /**
   * Performs an AJAX-based update of the list view contents.
   * @param id string the ID of the list view container
   * @param options map the AJAX request options (see jQuery.ajax API manual). By default,
   * the URL to be requested is the one that generates the current content of the list view.
   */
  $.fn.yiiListView.update = function (id, options) {
    var customError,
      settings = $.fn.yiiListView.settings[id];

    if (options && options.error !== undefined) {
      customError = options.error;
      delete options.error;
    }

    options = $.extend({
      type: settings.ajaxType,
      url: $.fn.yiiListView.getUrl(id),
      success: function (data, status) {
        $.each(settings.ajaxUpdate, function (i, v) {
          var id = '#' + v;
          $(id).replaceWith($(id, '<div>' + data + '</div>'));
        });
        if (settings.afterAjaxUpdate != undefined)
          settings.afterAjaxUpdate(id, data);
      },
      complete: function () {
        $('#' + id).removeClass(settings.loadingClass);
        yiiXHR[id] = null;
      },
      error: function (XHR, textStatus, errorThrown) {
        var ret, err;
        if (XHR.readyState === 0 || XHR.status === 0) {
          return;
        }
        if (customError !== undefined) {
          ret = customError(XHR);
          if (ret !== undefined && !ret) {
            return;
          }
        }
        switch (textStatus) {
          case 'timeout':
            err = 'The request timed out!';
            break;
          case 'parsererror':
            err = 'Parser error!';
            break;
          case 'error':
            if (XHR.status && !/^\s*$/.test(XHR.status)) {
              err = 'Error ' + XHR.status;
            } else {
              err = 'Error';
            }
            if (XHR.responseText && !/^\s*$/.test(XHR.responseText)) {
              err = err + ': ' + XHR.responseText;
            }
            break;
        }

        if (settings.ajaxUpdateError !== undefined) {
          settings.ajaxUpdateError(XHR, textStatus, errorThrown, err);
        } else if (err) {
          alert(err);
        }
      }
    }, options || {});

    if (options.data != undefined && options.type == 'GET') {
      options.url = $.param.querystring(options.url, options.data);
      options.data = {};
    }

    if (settings.ajaxVar)
      options.url = $.param.querystring(options.url, settings.ajaxVar + '=' + id);

    if (yiiXHR[id] != null) {
      yiiXHR[id].abort();
    }

    $('#' + id).addClass(settings.loadingClass);

    if (settings.beforeAjaxUpdate != undefined)
      settings.beforeAjaxUpdate(id);
    yiiXHR[id] = $.ajax(options);
  };

})(jQuery);
